<?php
namespace app\kefuswoole;

use think\facade\Cache;
use  think\facade\Log;
use think\swoole\Server;
use app\kefuswoole\Event;

class Swoole extends Server
{
    protected $host = '0.0.0.0'; //监听所有地址
    protected $port = 9501; //监听9501端口
    protected $serverType = 'socket';
    protected $option = [
        'worker_num' => 4, // 设置启动的Worker进程数
        'daemonize' => false, // 守护进程化（上线改为true）
        'backlog' => 128, // Listen队列长度
        'dispatch_mode' => 2, // 固定模式，保证同一个连接发来的数据只会被同一个worker处理
        'task_worker_num' => 20,

        // 心跳检测：每60秒遍历所有连接，强制关闭10分钟内没有向服务器发送任何数据的连接
        'heartbeat_check_interval' => 60,
        'heartbeat_idle_time' => 600,

        // ssl
        'ssl' => true,
        'ssl_cert_file' => __DIR__ . '/ssl.crt',
        'ssl_key_file' => __DIR__ . '/ssl.key',
    ];

    public function onWorkerStart($server, $worker_id)
    {
        //主进程定时维护FD
        if ($server->worker_id == 0 && !$server->taskworker){
            Event::statFd($server);
            $server->tick(30*1000, function($id) use ($server) {
                Event::statFd($server);
            });
        } 
    }

    //建立连接时回调函数
    public function onOpen($server, $req){
        $data = $req->get;
        $fd = $req->fd; //客户端标识
        //var_dump($req);
        echo "onOpen receive from {$req->fd}:{$req->server['query_string']},remote_addr:{$req->server['remote_addr']},request_time:{$req->server['request_time']}\n";
        //队列入库
        $taskData=[];
        $taskData['fd'] = $fd;
        $taskData['data'] = $data;
        $taskData['data']['type'] = 'onOpen';
        $taskData['data']['header'] = $req->header;
        $taskData['data']['server'] = $req->server;
        $server->task(json_encode($taskData), 0);
        try {
            Log::info('WebSocket请求连接，请求信息[' . json_encode($data) . ']');
            $resut = Event::userInit($server,$fd, $data);
            //$server->push($resut['fd'], $resut['data']);
        } catch (\Exception $e) {
            Log::error('WebSocket请求异常,异常信息：' . $e->getMessage().'错误地址：'. $e->getFile().$e->getLine());
            $res = ['code' => $e->getCode(), 'msg' => $e->getMessage(), 'data' => '', 'type' => ''];
        }
        if(isset($res)){
            $server->push($fd, json_encode($res));
        }
    }

    //接收数据时回调函数
    public function onMessage($server, $frame){
        $fd = $frame->fd;
        //用户心跳
        if ($frame->data == 'ping') {
            return $server->push($fd, 'pong');
        }
        $data = json_decode($frame->data, true);
        echo "onMessage receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";
        //队列入库
        $taskData=[];
        $taskData['fd'] = $fd;
        $taskData['data'] = $data;
        $server->task(json_encode($taskData), 0);
        try {
            Log::info('WebSocket请求开始，请求信息[' . json_encode($frame) . ']');
            $type = $data['type'];
            $messge = $data['data'];
            $resut = Event::$type($server,$frame->fd, $messge);
            $server->push($resut['fd'], $resut['data']);
        } catch (\Exception $e) {
            Log::error('WebSocket请求异常,异常信息：' . $e->getMessage().'错误地址：'. $e->getFile().$e->getLine());
            $res = ['code' => $e->getCode(), 'msg' => $e->getMessage(), 'data' => '', 'type' => ''];
        }
        if(isset($res)){
            $server->push($frame->fd, json_encode($res));
        }
    }

    //连接关闭时回调函数
    public function onClose($server, $fd){
        //队列入库
        $taskData=[];
        $taskData['fd'] = $fd;
        $taskData['data']['type'] = 'onClose';
        $server->task(json_encode($taskData), 0);

        $resut = Event::disconnect($server,$fd);
        echo "标识{$fd}关闭了连接\n";
    }

    public function onTask($server, $task_id, $from_id, $data)
    {
        echo "#### onTask ####".PHP_EOL;
        echo "#$task_id \t{$server->worker_id}\tonTask: [PID={$server->worker_pid}], data_len=".strlen($data).PHP_EOL;
        Event::addChatHistory($data);
        $server->finish($data);
    }

    public function onFinish($server, $task_id, $data)
    {
        echo "#### onFinish ####".PHP_EOL;
        echo "#$task_id \tfinished, data_len=".strlen($data).PHP_EOL;
    }

}
